<template>
  <div class="vertex-color">
    <div class="canvas" ref="canvas"></div>
  </div>
</template>

<script lang="ts">
import { Vue, Options } from 'vue-property-decorator';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
const scene =  new THREE.Scene();
const camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 0, 1800);
const point  = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300);
scene.add(point);
const ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
const renderer = new THREE.WebGLRenderer({
  alpha: true,
  antialias: true,
});
renderer.debug.checkShaderErrors = false;
renderer.setClearColor(new THREE.Color(), 0);
renderer.setPixelRatio(750 / window.innerWidth);
let shadowMesh!: THREE.Mesh;
let mouseX = 0; let mouseY = 0;
let windowHalfX = window.innerWidth / 2;
let windowHalfY = window.innerHeight / 2;
@Options({ components: {} })
export default class VertexColors extends Vue {
  public rect: DOMRect|null = null;

  public onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  }
  // eslint-disable-next-line @typescript-eslint/naming-convention
  public MouseMove(ev: MouseEvent) {
    mouseX = (ev.clientX - windowHalfX);
    mouseY = (ev.clientY - windowHalfY);
  }
  public play() {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (- mouseY - camera.position.y) * 0.05;
    camera.lookAt(scene.position);
    renderer.render(scene, camera);
  }
  public mounted() {
    this.rect = (this.$el as HTMLElement).getBoundingClientRect();
    renderer.setSize(this.rect.width, this.rect.height, false);
    (this.$refs.canvas as HTMLDivElement).append(renderer.domElement);

    const shadowTexture = new THREE.CanvasTexture(renderer.domElement);
    const shadowMaterial = new THREE.MeshBasicMaterial({ map: shadowTexture });
    const shadowGeo = new THREE.PlaneGeometry(300, 300, 1, 1);
    shadowMesh = new THREE.Mesh(shadowGeo, shadowMaterial);
    shadowMesh.position.y = -250;
    shadowMesh.rotation.x = - Math.PI / 2;
    scene.add(shadowMesh);

    shadowMesh = new THREE.Mesh(shadowGeo, shadowMaterial);
    shadowMesh.position.y = - 250;
    shadowMesh.position.x = - 400;
    shadowMesh.rotation.x = - Math.PI / 2;
    scene.add(shadowMesh);

    shadowMesh = new THREE.Mesh(shadowGeo, shadowMaterial);
    shadowMesh.position.y = - 250;
    shadowMesh.position.x = 400;
    shadowMesh.rotation.x = - Math.PI / 2;
    scene.add(shadowMesh);

    const radius = 200;
    const geometry1 = new THREE.IcosahedronGeometry(radius, 1);
    const { count } = geometry1.attributes.position;
    geometry1.setAttribute('color', new THREE.BufferAttribute(new Float32Array(count * 3), 3));
    const geometry2 = geometry1.clone();
    const geometry3 = geometry1.clone();
    const color = new THREE.Color();
    const positions1 = geometry1.attributes.position;
    const positions2 = geometry2.attributes.position;
    const positions3 = geometry3.attributes.position;
    const colors1 = geometry1.attributes.color;
    const colors2 = geometry2.attributes.color;
    const colors3 = geometry3.attributes.color;
    for (let i = 0; i < count; i ++) {
      color.setHSL((positions1.getY(i) / radius + 1) / 2, 1.0, 0.5);
      colors1.setXYZ(i, color.r, color.g, color.b);

      color.setHSL(0, (positions2.getY(i) / radius + 1) / 2, 0.5);
      colors2.setXYZ(i, color.r, color.g, color.b);

      color.setRGB(1, 0.8 - (positions3.getY(i) / radius + 1) / 2, 0);
      colors3.setXYZ(i, color.r, color.g, color.b);
    }
    const material = new THREE.MeshPhongMaterial({
      color: 0xffffff,
      flatShading: true,
      vertexColors: true,
      shininess: 0,
    });
    const wireframeMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, wireframe: true, transparent: true });
    let mesh!: THREE.Mesh;
    let wireframe!: THREE.Mesh;
    mesh = new THREE.Mesh(geometry1, material);
    wireframe = new THREE.Mesh(geometry1, wireframeMaterial);
    mesh.add(wireframe);
    mesh.position.x = - 400;
    mesh.rotation.x = - 1.87;
    scene.add(mesh);
    mesh = new THREE.Mesh(geometry2, material);
    wireframe = new THREE.Mesh(geometry2, wireframeMaterial);
    mesh.add(wireframe);
    mesh.position.x = 400;
    scene.add(mesh);
    mesh = new THREE.Mesh(geometry3, material);
    wireframe = new THREE.Mesh(geometry3, wireframeMaterial);
    mesh.add(wireframe);
    scene.add(mesh);

    renderer.setAnimationLoop(() => {
      this.play();
    });

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableZoom = false;

    document.addEventListener('mousemove', this.MouseMove);
    window.addEventListener('resize', this.onWindowResize);
  }
}
</script>

<style lang="postcss" scoped>
  .vertex-color{
    touch-action: none;
    position: absolute;
    left: 0;top: 0;
    width: 100%;height: 100%;
    background: #98bbd1;
 .canvas{
      position: absolute;
      left: 0;top: 0;
      width: 100%;height: 100%;
       :deep(canvas){
        width: 100%;height: 100%;
      }
    }
  }
</style>
